-module(data_mgr).
-behaviour(gen_server).
-include("define.hrl").
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
	create_database_ets(),
	load_json_datas(),
	erlang:send_after(1000, self(), check_and_update_datas),	
	{ok, []}.

handle_call(_Request, _From, State)->
	{reply, ok, State}.

handle_cast(_Request, State) -> 
	{noreply, State}.

handle_info(check_and_update_datas, State)->
	load_json_datas(),
	erlang:send_after(1000, self(), check_and_update_datas),
	{noreply, State};
handle_info(_Info, State)->
	{noreply, State}.

terminate(_Reason, _State) ->
	ok.

code_change(_OldVsn, State, _Extra) ->
	{ok, State}.

create_database_ets() ->
	ets:new(?DATA_TABLE_INFO, [protected, set, named_table, {keypos, #dataTableInfo.dataName}]).
	
load_json_datas() ->
    {ok, Cwd} = file:get_cwd(),
    FilePath = filename:join([Cwd, "data"]),
    AbsFiles = [filename:join([FilePath, File])||File<-filelib:wildcard("*.json", FilePath)],
    load_json_datas(AbsFiles).

load_json_datas([]) -> ok;
load_json_datas([AbsFile|T]) ->
    load_json_data(AbsFile),
    load_json_datas(T).

load_json_data(AbsFile) ->
	case check_file_data(AbsFile) of
		true -> ok;
		{false, BinaryDatas} -> 
			{struct, JsonDatas} = json:decode(BinaryDatas),
			FileName = utl:to_binary(filename:basename(AbsFile, ".json")),
			TableID = ets:new(utl:to_atom(FileName), [protected, set, {keypos, #dataKeyValue.key}]),
			{DataKeyValues, Keys} = 
				lists:foldl(fun({Key, {struct, Object}}, {AccDataKeyValues, AccDataKeys}) -> 
								{[#dataKeyValue{key = Key, value = Object}|AccDataKeyValues], [Key|AccDataKeys]} 
							end, {[], []}, JsonDatas),
			ets:insert(TableID, DataKeyValues),
			case ets:lookup(?DATA_TABLE_INFO, FileName) of
				[] -> 
					ets:insert(?DATA_TABLE_INFO, #dataTableInfo{dataName = FileName, tableID = TableID, keys = Keys, time = utl:time_now_sec(), md5 = erlang:md5(BinaryDatas)});
				[#dataTableInfo{tableID = OTableID}] ->	
					ets:insert(?DATA_TABLE_INFO, #dataTableInfo{dataName = FileName, tableID = TableID, keys = Keys, time = utl:time_now_sec(), md5 = erlang:md5(BinaryDatas)}),
					ets:delete(OTableID)
			end,
			log:info("load file name:~p's datas~n", [FileName]),
			ok
	end.

check_file_data(AbsFile) ->
	{MD5New, BinaryDatas} = get_abs_file_md5(AbsFile),
	MD5Old = get_database_md5(filename:basename(AbsFile, ".json")),
	case MD5New == MD5Old of
		true -> true;
		false -> {false, BinaryDatas}
	end.

get_abs_file_md5(Path) ->
	case file:read_file(Path) of
		{ok, Bins} -> {erlang:md5(Bins), Bins};
		{error, Reason} -> 
			log:error("get file name:~p data failed! reason: ~p~n", [Path, Reason]),
			throw({Path, Reason})
	end.

get_database_md5(FileName)->
	case ets:lookup(?DATA_TABLE_INFO, utl:to_binary(FileName)) of
		[]-> <<>>;
		[Object]->Object#dataTableInfo.md5
	end.